#version 120

varying vec3 position, normal, eyeVec;

uniform vec3 diffuseColor;
uniform float specularExp;

uniform sampler2D permSampler;
uniform sampler2D gradSampler2d;
uniform sampler2D gradSampler3d;
uniform sampler2D gradSampler4d;

uniform sampler2D colorMapSampler;

// add noise functions here
// Exercise 5.2, 5.3, 5.6
vec3 fade(vec3 t)
{
	return t * t * t * (t * (t * 6 - 15) + 10); // new curve
}

float perm(float x)
{
	return texture2D(permSampler, vec2(x, 0)).x;
}

float grad(float x, vec3 p)
{
	return dot(texture2D(gradSampler3d, vec2(x, 0)).xyz, p);
}

float inoise(vec3 p)
{
	vec3 P = mod(floor(p), 256f);
	p -= floor(p);
	vec3 f = fade(p);
	P = P/256.0;
	const float one = 1.0/256.0;

	// Hash coordinate for 6 of the 8 cube corners
  	float A = perm(P.x) + P.y;
  	vec4 AA;
  	AA.x = perm(A) + P.z;
	AA.y = perm(A + one) + P.z;
  	float B =  perm(P.x + one) + P.y;
  	AA.z = perm(B) + P.z;
  	AA.w = perm(B + one) + P.z;
	
	// And add blended results from 8 corners of cube
	
	return mix(
	  mix(
	    mix(grad(perm(AA.x), p),
	        grad(perm(AA.z), p+vec3(-1, 0, 0)), f.x),
	    mix(grad(perm(AA.y), p+vec3(0, -1, 0)),
	        grad(perm(AA.w), p+vec3(-1, -1, 0)), f.x),
	    f.y),
	  mix(
	    mix(grad(perm(AA.x+one), p+vec3(0, 0, -1)),
	        grad(perm(AA.z+one), p+vec3(-1, 0, -1)), f.x),
	    mix(grad(perm(AA.y+one), p+vec3(0, -1, -1)),
	        grad(perm(AA.w+one), p+vec3(-1, -1, -1)), f.x),
	    f.y),
	  f.z
	);
}

#define PI (3.1415926535)

/* Stripes */
float stripes(float x, float f)
{
	float t = .5 + .5 * sin(f * 2*PI * x);
	return t * t - 0.5;
}

/* Turbulence */
float turbulence(vec3 pos, float f)
{
	float t = -.5;
	float W = 800;
	for ( ; f <= W/12 ; f *= 2) // W = Image width in pixels
		t += abs(inoise(pos) / f);
	return t;
}

//=========================================================================================
// Main Function
//=========================================================================================

void main()
{
    permSampler; gradSampler2d; gradSampler3d; gradSampler4d; colorMapSampler; diffuseColor;

    vec3 N = normal;
    
    // add bump mapping here
    // Exercise 5.5
    
    N = normalize(N);

	/* Uncomment for Ferrero-Rocher (with the wood color below) */
	
	float eps = 0.1;
	float x = position.x*10;
	float y = position.y*10;
	float z = position.z*10;
	float F = 0.5+inoise(position*10);
	float Fx = 0.5+inoise(vec3(x+eps, y, z));
	float Fy = 0.5+inoise(vec3(x, y+eps, z));
    float Fz = 0.5+inoise(vec3(x, y, z+eps));
	vec3 dF = (vec3(Fx, Fy, Fz)-F)/eps;
	N = normalize(N-dF);
	
    
    //vec3 color = vec3(0.75,0.3,0.3);
    //vec3 color = position;
    float noise = 0.5+inoise(position*25);
	//float noise = 0.2*stripes(position.x + 2 * turbulence(position, 1.0), 5);
	//float noise = 0.5 - 2*turbulence(position, 1.0);
    //vec3 color = vec3(0.65+noise, 0.39+noise, 0.15+noise); // wood
	vec3 color = vec3(noise, noise, noise);
    
    /************************/
	/* REMOVE IN YOUR SOLUTION */
    //vec3 color = diffuseColor; //to use the property of the mesh
    
    // to use color maps:
	//vec3 color = texture2D( colorMapSampler, vec2(value,0) ).xyz;
    
    // to remove errors in case these variables are not used
    //diffuseColor; colorMapSampler; noiseFunction(vec3(0.,0.,0.));
    /************************/

	vec4 final_color = vec4(0.0);
	//vec3 L = normalize(lightDir);
    
    // initialize 3 lights
	vec3 L1 = normalize(vec3(1,1,1));
	vec3 L2 = normalize(vec3(0,0,-1));
	vec3 L3 = normalize(vec3(-1,-0.3,-2));
	float lambertTerm1 = max(0.0, dot(N, L1));
	float lambertTerm2 = max(0.0, dot(N, L2));
	float lambertTerm3 = max(0.0, dot(N, L3));
	float ambientTerm = 0.3;
	//if(lambertTerm > 0.0)
	{
		final_color += vec4(color, 1.0) * (0.8*(lambertTerm1+lambertTerm2+lambertTerm3)+ambientTerm);	
		vec3 E = normalize(eyeVec);
		vec3 R1 = reflect(-L1, N);
		vec3 R2 = reflect(-L2, N);
		vec3 R3 = reflect(-L3, N);
		float specular1 = pow(max(dot(R1, E), 0.0), specularExp/10.0);
		float specular2 = pow(max(dot(R2, E), 0.0), specularExp/10.0);
		float specular3 = pow(max(dot(R3, E), 0.0), specularExp/10.0);
		final_color += vec4(color, 1.0)*1.0*(specular1+specular2+specular3);	
	}

	gl_FragColor = final_color;	
	
}
